package cn.iocoder.yudao.module.bpm.controller.admin.definition;

import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.yudao.module.bpm.api.task.dto.*;
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.common.BpmCommonHandleVO;
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.common.BpmHandleStatisticsRespVO;
import cn.iocoder.yudao.module.bpm.service.definition.BpmCommonService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.StringUtils;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.engine.*;
import org.flowable.engine.runtime.Execution;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.image.ProcessDiagramGenerator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;

import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;

@Tag(name = "管理后台 - 流程公共controller")
@RestController
@RequestMapping("/bpm/common")
public class BpmCommonController {

    @Autowired
    private RuntimeService runtimeService;

    @Autowired
    private RepositoryService repositoryService;

    @Autowired
    private ProcessEngine processEngine;

    @Autowired
    private TaskService taskService;

    @Autowired
    private BpmCommonService bpmCommonService;


    /**
     * 查询正在办理的流程分页
     *
     * @throws Exception
     */
    @GetMapping("/queryHandleFlowPage")
    @Operation(summary = "查询待办流程分页")
    public CommonResult<PageResult<BpmCommonHandleDTO>> queryHandleFlowPage(BpmCommonHandlePageDTO pageDTO) throws Exception {
        pageDTO.setPageNo((pageDTO.getPageNo() - 1) * pageDTO.getPageSize());
        pageDTO.setUserCode("" + SecurityFrameworkUtils.getLoginUserId());
        // 查询当前登录人的待办
        return success(bpmCommonService.selectHandleFlowPage(pageDTO));
    }

    /**
     * 查询待办统计数据
     * @Author 王铁
     * @Description TODO
     * @Date 2024/10/24 10:55
     * @Version 1.0
     */
    @GetMapping("/getHandleStatistics")
    @Operation(summary = "查询待办统计数据")
    public CommonResult<List<BpmHandleStatisticsRespVO>> getHandleStatistics(BpmCommonHandleVO reqVO)  {
        // 查询当前登录人的待办
        return success(bpmCommonService.getHandleStatistics(reqVO));
    }

    /**
     * 查询正在办理的流程分页
     *
     * @throws Exception
     */
    @GetMapping("/queryHandleDoneFlowPage")
    @Operation(summary = "查询已办流程分页")
    public CommonResult<PageResult<BpmCommonHandleDTO>> queryHandleDoneFlowPage(BpmCommonHandlePageDTO pageDTO) throws Exception {
        pageDTO.setPageNo((pageDTO.getPageNo() - 1) * pageDTO.getPageSize());
        pageDTO.setUserCode("" + SecurityFrameworkUtils.getLoginUserId());
        // 查询当前登录人的待办
        return success(bpmCommonService.selectHandleDoneFlowPage(pageDTO));
    }

    /**
     * 根据流程名称查询待办流程总数
     *
     * @throws Exception
     */
    @GetMapping("/queryHandleTotalByName")
    @Operation(summary = "根据流程名称查询待办流程总数")
    public CommonResult<List<BpmCommonHandleTotalDTO>> queryHandleTotalByName() throws Exception {
        // 查询当前登录人的待办
        return success(bpmCommonService.selectHandleTotal("" + SecurityFrameworkUtils.getLoginUserId()));
    }

    /**
     * 根据流程名称查询已办流程总数
     *
     * @throws Exception
     */
    @GetMapping("/queryHandleDoneTotalByName")
    @Operation(summary = "根据流程名称查询已办流程总数")
    public CommonResult<List<BpmCommonHandleTotalDTO>> queryHandleDoneTotalByName() throws Exception {
        // 查询当前登录人的已办
        return success(bpmCommonService.selectHandleDoneTotal("" + SecurityFrameworkUtils.getLoginUserId()));
    }

    /**
     * 创建流程
     *
     * @throws Exception
     */
    @PostMapping("/createFlow")
    @Operation(summary = "创建流程")
    public CommonResult<BpmCommonCreateRespDTO> createFlow(@RequestBody BpmCommonCreateReqDTO vo) throws Exception {
        return success(bpmCommonService.createProcessInstance(vo.getId(), vo.getKey(), vo.getVariables()));
    }

    /**
     * @param vo
     * @throws Exception
     */
    @PostMapping("/createAndSubmitFlow")
    @Operation(summary = "创建并提交流程")
    public CommonResult<BpmCommonCreateRespDTO> createAndSubmitFlow(@RequestBody BpmCommonCreateReqDTO vo) throws Exception {
        //判断是否存在提交处理人，如不存在就自己处理
        if (StringUtils.isBlank(vo.getAssignee())) {
            vo.setAssignee("" + SecurityFrameworkUtils.getLoginUserId());
        }
        //将处理人存入环境变量中
        vo.getVariables().put("assignee", vo.getAssignee());
        return success(bpmCommonService.createInstanceAndCompleteTask(vo.getId(), vo.getReason(), vo.getKey(), vo.getVariables()));
    }

    /**
     * @param vo
     * @throws Exception
     */
    @PostMapping("/submitFlow")
    @Operation(summary = "提交流程")
    public CommonResult<BpmCommonCreateRespDTO> submitFlow(@RequestBody BpmCommonCreateReqDTO vo) throws Exception {
        //判断是否存在提交处理人，如不存在就自己处理
        if (StringUtils.isBlank(vo.getAssignee())) {
            vo.setAssignee("" + SecurityFrameworkUtils.getLoginUserId());
        }
        //将处理人存入环境变量中
        vo.getVariables().put("assignee", vo.getAssignee());
        return success(bpmCommonService.completeTask(vo.getProcessInstanceId(), vo.getReason(), vo.getVariables()));
    }

    /**
     * @param resp
     * @param processId
     * @throws Exception
     */
    @PostMapping("/showFlow")
    @Operation(summary = "显示流程图")
    public void showFlow(String processId, HttpServletResponse resp) throws Exception {
        ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult();
        if (pi == null) {
            return;
        }
        List<Execution> executions = runtimeService.createExecutionQuery().processInstanceId(processId).list();

        List<String> activityIds = new ArrayList<>();
        List<String> flows = new ArrayList<>();
        for (Execution exe : executions) {
            List<String> ids = runtimeService.getActiveActivityIds(exe.getId());
            activityIds.addAll(ids);
        }

        /**
         * 生成流程图
         */
        BpmnModel bpmnModel = repositoryService.getBpmnModel(pi.getProcessDefinitionId());
        ProcessEngineConfiguration engconf = processEngine.getProcessEngineConfiguration();
        ProcessDiagramGenerator diagramGenerator = engconf.getProcessDiagramGenerator();
        InputStream in = diagramGenerator.generateDiagram(bpmnModel, "png", activityIds, flows, engconf.getActivityFontName(), engconf.getLabelFontName(), engconf.getAnnotationFontName(), engconf.getClassLoader(), 1.0, false);
        OutputStream out = null;
        byte[] buf = new byte[1024];
        int legth = 0;
        try {
            out = resp.getOutputStream();
            while ((legth = in.read(buf)) != -1) {
                out.write(buf, 0, legth);
            }
        } finally {
            if (in != null) {
                in.close();
            }
            if (out != null) {
                out.close();
            }
        }
    }


    /**
     * 通过processDefinition.id和resType导出流程XML或图片资源
     *
     * @param id       processDefinition.id
     * @param resType  取值 “image/png”或“text/xml”
     * @param response
     * @throws Exception
     */
    @GetMapping(value = "/exp")
    @Operation(summary = "通过processDefinition.id和resType导出流程XML或图片资源")
    public void resourceRead(@RequestParam("id") String id, @RequestParam("resType") String resType, HttpServletResponse response) throws Exception {
        /** resType取值 “image/png”或“text/xml” **/
        InputStream resourceAsStream = bpmCommonService.resourceRead(id, resType);
        byte[] b = new byte[1024];
        int len = -1;
        while ((len = resourceAsStream.read(b, 0, 1024)) != -1) {
            response.getOutputStream().write(b, 0, len);
        }
    }
}
